/*
 *  Phrase.h
 *  OfflineTranslator
 *
 *  Created by PH on 5.9.10.
 *  Copyright 2010 Petr Homola. All rights reserved.
 *
 */

#ifndef NLP_PHRASE_H_
#define NLP_PHRASE_H_

#include "global.h"
#include <iostream>
#include <string>
#include <map>
#include <assert.h>
#include "AVM.h"

namespace nlp {

	using namespace std;
#ifdef TR1
	using namespace std::tr1;
#endif
	
	class PhrasePath;
	
	class Phrase {
		
	private:
		//string desc;
		int begin;
		int end;
		int level;
		bool used;
		shared_ptr<AVM> avm;
		bool transferredLexically;
		bool transferredStructurally;
		mutable int penalty;
		//string desc;
		
	public:
		Phrase(const shared_ptr<AVM>& _avm) : avm(new AVM(_avm)) {
			//desc = d;
			begin = 0; end = 0;
			//avm->retain();
			level = 0;
			transferredLexically = false;
			transferredStructurally = false;
			penalty = -1;
			//desc = "";
			//cout << "Phrase: 1 -- " << description() << endl;
		}
		
		Phrase(const Phrase* p) : avm(new AVM(p->avm)), begin(p->begin), end(p->end), level(p->level) {
			transferredLexically = p->transferredLexically;
			transferredStructurally = p->transferredStructurally;
			penalty = p->penalty;
		}
		
		Phrase(const shared_ptr<AVM>& _avm, int b, int e) : avm(new AVM(_avm)), begin(b), end(e), level(0) {
			transferredLexically = false;
			transferredStructurally = false;
			penalty = -1;
			//desc = "";
		}
		
		~Phrase() {
			//delete avm;
			//avm->release();
			//cout << "Phrase dealloced" << endl;
		}
		
		int getPenalty() const {
			if (penalty == -1) penalty = avm->getTreePenalty();
			return penalty;
		}
		
		bool isTransferredLexically() const { return transferredLexically; }
		
		void setTransferredLexically() { transferredLexically = true; }
		
		bool isTransferredStructurally() const { return transferredStructurally; }
		
		void setTransferredStructurally() { transferredStructurally = true; }
		
		shared_ptr<AVM> getAvm() const { return avm; }
		
		void setAvm(shared_ptr<AVM> _avm) { avm = _avm; }
		
		void setLevel(int l) { level = l; }
		
		int getLevel() const { return level; }
		
		string description() const {
			__block string line = "";
			const Phrase* me = this;
			avm->enumerateLeftChildren(BLOCK(&line, me)(const string& key, const shared_ptr<AVM>& _avm) {
				if (_avm->get("silent").description() != "1") line += me->description(_avm) + " ";
			}, true);
			line += description(avm); //+ "/" + avm->get("order").description();
			avm->enumerateRightChildren(BLOCK(&line, me)(const string& key, const shared_ptr<AVM>& _avm) {
				if (_avm->get("silent").description() != "1") line += " " + me->description(_avm);
			}, true);
			return line;
		}
		
		void linearize(const string& prefix, const PhrasePath* path, BLOCKVAR(block, void, const string&)) const;
				
		string description(shared_ptr<AVM> _avm) const {
			//if (desc.size() > 0) return desc;
			Value value = _avm->get("targetForm");
			if (value.isEmpty() == true) value = _avm->get("targetLemma");
			if (value.isEmpty() == true) {
				value = _avm->get("form");
				//cout << Value(_avm->get("form").description() + "/" + _avm->get("lemma").description()).description() << endl;
			}
			//if (value.isEmpty()) return _avm->description(); else return value.description();
			string desc = value.isEmpty() ? _avm->description() : value.description();
			return desc + " (" + _avm->get("order").description() + ")";
		}
		
		int getBegin() const { return begin; }
		
		int getEnd() const { return end; }
		
		bool isUsed() { return used; }
		
		void setUsed(bool u) { used = u; }
		
	};
	
}

#endif
